#include "Server.h"

// 判断文件描述符集合的最大值
#define FDS_MAX(FD_1, FD_2) FD_1 > FD_2 ? FD_1 : FD_2

// 设定最大连接客户端数量
#define LIN_MAX 3

int main(int argc, char const *argv[])
{
    /************** 测试参数合法性 **************/
    if (argc != 2)
    {
        printf("输入的格式错误 %s port\n", argv[0]);
        exit(1);
    }

    /************** 声明变量 **************/
    int sock_client; // 客户端 套接字
    int sock_server; // 客户端 套接字

    int sock_client_arr[LIN_MAX] = {0};                 // 客户端 套接字 数组
    int sock_client_len = 0;                            // 用于管理 客户端套接字长度

    

    char buf_recv[1024];                                // 接收字符串
    char buf_send[1024] = "恭喜你,通讯成功,我已收到\n";   // 发送字符串
    char buf_recv_len = 0;                              // 记录接收字符串长度 用于判定是否断开连接

    int fds_num = 0;                                    // 多路IO 就绪文件描述符个数


    /************** 初始化TCP **************/
    // atoi(argv[1])    端口号
    // sock_server      服务器套接字
    sock_server = tcp_server_init(atoi(argv[1]));

    /************** 监听 **************/
    if (-1 == listen(sock_server, LIN_MAX))
    {
        ERRLOG("监听失败");
        close(sock_server);
        return -3;
    }

    /************** 多路IO **************/
    // 声明集合
    fd_set Tcp_client_fds;      // 母本
    fd_set Tcp_client_fds_temp; // 副本

    // 声明集合的的最大值
    unsigned int Tcp_fds_max = 0;

    // 清空母本集合
    FD_ZERO(&Tcp_client_fds);

    // 将服务器套接字 加入到 集合中
    FD_SET(sock_server, &Tcp_client_fds);
    // 更新最大值
    Tcp_fds_max = FDS_MAX( sock_server , Tcp_fds_max);

    while (1)
    {
        // 清空副本
        FD_ZERO(&Tcp_client_fds_temp);

        // 母本赋值给副本
        Tcp_client_fds_temp = Tcp_client_fds;

        // 多路IO复用
        // fds_num  存储返回值 
            // fds_num == -1 代表错误
            // fds_num > 0 代表读取到的就绪套接字个数
            // fds_num = 0 超时
        fds_num = select(Tcp_fds_max + 1, &Tcp_client_fds_temp, NULL, NULL, NULL);
        if(fds_num == -1)
        {
            printf("select 错误\n");
            continue;
        }

        /************** 新用户连接 **************/
        if (FD_ISSET(sock_server, &Tcp_client_fds_temp))
        {
            // 等待客户端连接
            sock_client = accept(sock_server, NULL, NULL);
            if (sock_client == -1)
            {
                ERRLOG("连接失败");
                return 0;
            }

            // 判断是否超过最大连接数
            if(sock_client_len >= LIN_MAX + 1)
            {
                send(sock_client , "超过客户端最大连接数量", strlen("超过客户端最大连接数量") , 0);
                close(sock_client);
                printf("超过客户端最大连接数量\n");
                continue;
            }

            // 连接后 写入到数组中
            sock_client_arr[sock_client_len++] = sock_client;


            printf("连接成功 套接字:%d max = %d\n" , sock_client , Tcp_fds_max);

            // 将客户端套接字 加入到 集合中
            FD_SET(sock_client, &Tcp_client_fds);
            // 获取最大值
            Tcp_fds_max = FDS_MAX(sock_client, Tcp_fds_max);
        }

        /************** 客户端信息 **************/
        else
        {
            // 遍历集合
            for (size_t i = 0; i < sock_client_len && fds_num != 0; i++ )
            {
                // 判断 那个 套接字 就绪
                if(FD_ISSET( sock_client_arr[i] , &Tcp_client_fds_temp))
                { 
                    // 对套接字就绪个数做减一操作  优化 扫描次数
                    fds_num--;
                    // 清空接收套接字
                    memset(buf_recv , 0 , sizeof(buf_recv));
                    // 接收信息
                    buf_recv_len = recv(sock_client_arr[i], buf_recv , sizeof(buf_recv) , 0);
                    if(buf_recv_len == 0)  // 客户端退出
                    {
                        // 从集合中删除
                        FD_CLR(sock_client_arr[i] , &Tcp_client_fds);
                        // 如果删除的是最大的套接字 则需要将 Tcp_fds_max 减一
                        if (sock_client_arr[i] == Tcp_fds_max)
                        {
                            Tcp_fds_max--;
                        }
                        // 关闭套接字
                        close(sock_client_arr[i]);
                        continue;
                    }
                    // 打印接收到的数据
                    printf("接收信息:%s\n" , buf_recv);
                    // 向客户端发送一个信息
                    send(sock_client_arr[i], buf_send , strlen(buf_send) , 0);
                }
            }
        }

    }

    return 0;
}
